<template>
  <div class="online-report-form">
    <van-nav-bar class="header"
      :title="formConfig.pageName"
      left-arrow
      @click-left="onBack()"
    >
      <template #left>
        <van-icon name="arrow-left" size="18" color="#3B3938" />
      </template>
    </van-nav-bar>
    <online-filter-box :supportSort="false"
      style="background: white; padding: 0px 18px; flex-shrink: 0;"
      @reset="onReset"
    >
      <!-- 过滤字段 -->
      <online-custom-block subWidgetClass="filter-item"
        :widgetList="filterWidgetList"
      />
    </online-filter-box>
    <van-form class="main-box" ref="form"
      :label-width="(formConfig.labelWidth || 100) + 'px'"
      label-align="left"
    >
      <online-custom-block :widgetList="chartWidgetList" />
    </van-form>
    <!-- 弹出子表单 -->
    <van-popup
      v-model="showSubPage"
      position="right"
      get-container="body"
      :overlay="false"
      style="height: 100vh; width: 100vw; background: #F6F6F6;"
    >
      <online-report-form :pageId="subPageId" :params="subPageParams" @close="onCloseSubPage" />
    </van-popup>
  </div>
</template>

<script>
import { Notify } from 'vant';
import { mapGetters, mapMutations } from 'vuex';
import { formatDate, findItemFromList, findTreeNode } from '@/utils';
import { getAllWidgetList, isChart } from './utils.js';
import { ReportDatasetController, ReportOperationController, ReportDictController, ReportPageController } from '@/api/reportController.js';
import { DictionaryController } from '@/api';

export default {
  name: 'reportForm',
  props: {
    formConfig: {
      type: Object
    },
    height: {
      type: String
    },
    // 是否表单编辑模式
    isEdit: {
      type: Boolean
    },
    // 当前选中组件
    currentWidget: {
      type: Object
    },
    fullscreen: {
      type: Boolean
    },
    // 表单参数
    params: {
      type: String
    },
    mode: {
      type: String,
      default: 'mobile'
    }
  },
  provide () {
    return {
      form: () => {
        return {
          ...this.formConfig,
          mode: this.mode,
          isEdit: this.isEdit,
          formType: this.SysOnlineFormType.REPORT,
          readOnly: false,
          getWidgetValue: this.getWidgetValue,
          getWidgetVisible: this.getWidgetVisible,
          onValueChange: this.onValueChange,
          onWidgetValueChange: this.onWidgetValueChange,
          getDictDataList: this.getDictDataList,
          getQueryParam: this.getQueryParam,
          listDataWithGroup: this.listDataWithGroup,
          listDictData: this.listDictData,
          listColumnData: this.listColumnData,
          loadDatasetInfo: this.loadDatasetInfo,
          getDropdownParams: this.getDropdownParams,
          onChartDblClick: this.onChartDblClick,
          isActive: (widget) => {
            return this.currentWidget === widget;
          }
        }
      }
    }
  },
  data () {
    return {
      isReady: false,
      formData: {},
      datasetMap: new Map(),
      dictMap: new Map(),
      showSubPage: false,
      subPageId: undefined,
      subPageParams: undefined
    }
  },
  methods: {
    onBack () {
      this.$router.go(-1);
    },
    onCloseSubPage (refresh) {
      this.showSubPage = false;
    },
    onReset () {
      if (Array.isArray(this.filterWidgetList)) {
        this.filterWidgetList.forEach(widget => {
          this.onValueChange(widget, undefined);
        });
      }
    },
    loadReportPage (pageId) {
      return new Promise((resolve, reject) => {
        ReportPageController.view(this, {
          pageId: pageId
        }).then(res => {
          let temp = {
            pageId: res.data.pageId,
            pageName: res.data.pageName,
            pageCode: res.data.pageCode,
            groupId: res.data.groupId,
            pageJson: res.data.pageJson,
            formInfo: res.data.pageJson ? JSON.parse(res.data.pageJson) : {}
          }
          let formInfo = temp.formInfo.pc;
          let formConfig = null;
          if (formInfo != null) {
            formConfig = {
              pageId: temp.pageId,
              pageName: temp.pageName,
              pageCode: temp.pageCode,
              gutter: formInfo.gutter || 20,
              labelWidth: formInfo.labelWidth || 100,
              labelPosition: formInfo.labelPosition || 'left',
              customFieldList: formInfo.customFieldList || [],
              filterItemWidth: formInfo.filterItemWidth || 350,
              widgetList: formInfo.widgetList || [],
              paramList: formInfo.paramList || []
            }
          }

          resolve(formConfig);
        }).catch(e => {
          reject(e);
        });
      });
    },
    onInput (widgetList) {
      this.formConfig.widgetList = widgetList;
    },
    onWidgetClick (widget) {
      this.$emit('widgetClick', widget);
    },
    initFormWidget (widget) {
      if (widget == null) return;
      if (widget.props && widget.props.dictInfo) {
        let dict = this.dictMap.get(widget.props.dictInfo.dictId);
        widget.props.dictInfo.dict = dict;
      }
      if (widget.eventInfo == null) {
        widget.eventInfo = {};
      }
      if (Array.isArray(widget.childWidgetList)) {
        widget.childWidgetList = widget.childWidgetList.map(subWidget => {
          return this.initFormWidget(subWidget);
        });
      }
      if (widget && widget.props && widget.props.datasetInfo && widget.props.datasetInfo.datasetId) {
        let dataset = this.datasetMap.get(widget.props.datasetInfo.datasetId);
        return {
          ...widget,
          dataset: dataset,
          columnList: (dataset || {}).columnList
        }
      } else {
        return {
          ...widget
        }
      }
    },
    initFormData () {
      return new Promise((resolve, reject) => {
        this.getAllWidget.forEach(widget => {
          this.$set(this.formData, widget.variableName, undefined);
        });
        this.loadAllDataset(this.formConfig.widgetList).then(res => {
          return this.loadReportDictList();
        }).then(res => {
          this.formConfig.widgetList = this.formConfig.widgetList.map(widget => {
            return this.initFormWidget(widget);
          });
          this.initPageWatch();
          resolve();
        }).catch(e => {
          console.log(e);
          reject(e);
        });
      });
    },
    buildWatch (widget, filter) {
      if (filter.filterValueType === this.FilterValueKind.FORM_PARAM) {
        // 报表参数
        this.$watch('formParams.' + filter.paramValue, () => {
          if (widget.widgetImpl) widget.widgetImpl.reset();
        });
      } else if (filter.filterValueType === this.FilterValueKind.WIDGET_DATA) {
        // 过滤组件
        let filterWidget = findItemFromList(this.getAllWidget, filter.formWidgetId, 'widgetId');
        if (filterWidget != null) {
          this.$watch('formData.' + filterWidget.variableName, () => {
            if (widget.widgetImpl) widget.widgetImpl.reset();
          });
        }
      }
    },
    buildDropdownWatch (widget) {
      if (widget && Array.isArray((widget.props.dictInfo || {}).paramList)) {
        widget.props.dictInfo.paramList.forEach(param => {
          if (param.dictValueType === this.SysOnlineParamValueType.TABLE_COLUMN && param.dictValue != null) {
            let filterWidget = findItemFromList(this.getAllWidget, param.dictValue, 'widgetId');
            if (filterWidget != null) {
              this.$watch('formData.' + filterWidget.variableName, () => {
                this.formData[widget.variableName] = undefined;
                if (widget && widget.widgetImpl && typeof widget.widgetImpl.reset === 'function') {
                  widget.widgetImpl.reset();
                }
              });
            }
          }
        });
      }
    },
    initPageWatch () {
      this.getAllWidget.forEach(widget => {
        if (isChart(widget.widgetType) && widget.props.datasetInfo) {
          // 组件过滤
          if (Array.isArray(widget.props.datasetInfo.filterList)) {
            widget.props.datasetInfo.filterList.forEach(filter => {
              this.buildWatch(widget, filter);
            });
          }
          // 数据集过滤
          if (Array.isArray(widget.props.datasetInfo.datasetFilterParams)) {
            widget.props.datasetInfo.datasetFilterParams.forEach(filter => {
              this.buildWatch(widget, filter);
            });
          }
          // 指标过滤
          if (Array.isArray(widget.props.datasetInfo.valueColumnList)) {
            widget.props.datasetInfo.valueColumnList.forEach(valueColumn => {
              if (valueColumn && Array.isArray(valueColumn.filterList)) {
                valueColumn.filterList.forEach(filter => {
                  this.buildWatch(widget, filter);
                });
              }
            });
          }
        }
        // 下拉数据过滤
        this.buildDropdownWatch(widget);
      });
    },
    loadDataset (datasetId) {
      return new Promise((resolve, reject) => {
        let params = {
          datasetId: datasetId
        }
        ReportDatasetController.view(this, params).then(res => {
          try {
            let info = JSON.parse(res.data.datasetInfo);
            res.data.datasetParamList = info.paramList;
          } catch (e) {
            res.data.datasetParamList = [];
          }
          this.datasetMap.set(datasetId, res.data);
          resolve(res.data);
        }).catch(e => {
          reject(e);
        });
      });
    },
    getAllDatasetIdsByWidgetList (widgetList, datasetIdList = []) {
      if (Array.isArray(widgetList)) {
        widgetList.forEach(widget => {
          if (widget && widget.props && widget.props.datasetInfo && widget.props.datasetInfo.datasetId) {
            if (datasetIdList.indexOf(widget.props.datasetInfo.datasetId) === -1) {
              datasetIdList.push(widget.props.datasetInfo.datasetId);
            }
          }
          this.getAllDatasetIdsByWidgetList(widget.childWidgetList, datasetIdList);
        });
      }
    },
    loadAllDataset (widgetList) {
      let datasetIdList = [];
      this.getAllDatasetIdsByWidgetList(widgetList, datasetIdList);
      return Promise.all(datasetIdList.map(datasetId => {
        return this.loadDataset(datasetId);
      }));
    },
    loadReportDictList () {
      this.dictMap = new Map();
      return new Promise((resolve, reject) => {
        DictionaryController.dictReportDict(this, {}).then(res => {
          res.getList().forEach(item => {
            item.dictData = item.dictDataJson ? JSON.parse(item.dictDataJson) : undefined;
            this.dictMap.set(item.id, item);
          });
          resolve();
        }).catch(e => {
          reject(e);
        });
      });
    },
    getSystemVariableValue (systemVariableType) {
      switch (systemVariableType) {
        case this.OnlineSystemVariableType.CURRENT_USER: return this.getUserInfo.showName;
        case this.OnlineSystemVariableType.CURRENT_DEPT: return this.getUserInfo.deptName;
        case this.OnlineSystemVariableType.CURRENT_DATE: return formatDate(new Date(), 'YYYY-MM-DD');
        case this.OnlineSystemVariableType.CURRENT_TIME: return formatDate(new Date(), 'YYYY-MM-DD HH:mm:ss');
        case this.OnlineSystemVariableType.FLOW_CREATE_USER: return (this.flowInfo || {}).processInstanceInitiator || this.getUserInfo.showName;
      }
      return undefined;
    },
    getWidgetValue (widget) {
      return this.formData[widget.variableName];
    },
    getWidgetVisible (widget) {
      if (widget == null || widget.eventInfo == null) return true;
      if (typeof widget.eventInfo[this.OnlineFormEventType.VISIBLE] === 'function') {
        return widget.eventInfo[this.OnlineFormEventType.VISIBLE]();
      } else {
        return true;
      }
    },
    onValueChange (widget, value) {
      this.formData[widget.variableName] = value;
    },
    onWidgetValueChange (widget, value, dictData) {
      if (widget == null || widget.eventInfo == null) return;
      let fun = this.getScriptFunction(widget.eventInfo, this.OnlineFormEventType.CHANGE);
      fun && fun(value);
    },
    getDictDataList (dictInfo, params) {
      if (dictInfo == null || dictInfo.id == null) return Promise.resolve([]);
      return this.listDictData(dictInfo.id, params);
    },
    getScriptFunction (eventInfo, eventType) {
      if (eventInfo && typeof eventInfo[eventType] === 'function') {
        return eventInfo[eventType];
      } else {
        return null;
      }
    },
    getParamValue (valueType, valueData) {
      switch (valueType) {
        case this.SysOnlineParamValueType.TABLE_COLUMN:
        {
          let widget = findItemFromList(this.getAllWidget, valueData, 'widgetId');
          return widget ? this.formData[widget.variableName] : undefined;
        }
        case this.SysOnlineParamValueType.STATIC_DICT:
          return Array.isArray(valueData) ? valueData[1] : undefined;
        case this.SysOnlineParamValueType.INPUT_VALUE:
          return valueData;
      }
    },
    getDropdownParams (widget) {
      if (Array.isArray(widget.props.dictInfo.paramList)) {
        let params = {};
        for (let i = 0; i < widget.props.dictInfo.paramList.length; i++) {
          let dictParam = widget.props.dictInfo.paramList[i];
          if (dictParam.dictValue == null || dictParam.dictValueType == null) continue;
          let widgetData = this.getParamValue(dictParam.dictValueType, dictParam.dictValue);
          if (widgetData == null) return null;
          params[dictParam.dictParamName] = widgetData;
        }
        return params;
      } else {
        return {};
      }
    },
    getQueryParam (filter) {
      if (filter.filterValueType === this.FilterValueKind.FORM_PARAM) {
        let formParam = this.formParams[filter.paramValue];
        if (formParam != null) {
          if (formParam.filterValueType === this.FilterValueKind.INNER_VARIABLE) {
            // 内置变量参数
            return {
              ...filter,
              filterValueType: this.FilterValueKind.INNER_VARIABLE,
              paramValue: formParam
            }
          } else {
            return {
              ...filter,
              paramValue: formParam
            }
          }
        } else {
          return {
            ...filter,
            paramValue: undefined
          }
        }
      } else if (filter.filterValueType === this.FilterValueKind.WIDGET_DATA) {
        let filterWidget = findItemFromList(this.getAllWidget, filter.formWidgetId, 'widgetId');
        let paramValue, dateRange;
        if (filterWidget != null) {
          paramValue = this.formData[filterWidget.variableName];
          if (filterWidget.widgetType === this.ReportWidgetType.Cascader) {
            if (Array.isArray(paramValue)) {
              paramValue = paramValue[paramValue.length - 1];
            } else {
              paramValue = undefined;
            }
          }
          if (paramValue === '') paramValue = undefined;
          if (filterWidget.widgetType === this.ReportWidgetType.DateRange || filterWidget.widgetType === this.ReportWidgetType.Date) {
            switch (filterWidget.props.type) {
              case 'daterange':
                dateRange = 'date';
                break;
              case 'monthrange':
                dateRange = 'month';
                break;
              case 'datetimerange':
              case 'datetime':
                dateRange = undefined;
                break;
              default:
                dateRange = filterWidget.props.type;
            }
          }
        }
        return {
          ...filter,
          dateRange,
          paramValue
        }
      } else {
        return {
          ...filter
        }
      }
    },
    listDataWithGroup (params) {
      return new Promise((resolve, reject) => {
        let finalParams = {
          ...params,
          pageCode: this.formConfig.pageCode
        }
        let httpCall = this.isEdit ? ReportOperationController.previewDataWithGroup(this, finalParams) : ReportOperationController.listDataWithGroup(this, finalParams);
        httpCall.then(res => {
          resolve(res.data);
        }).catch(e => {
          reject(e);
          console.log(e);
        });
      });
    },
    listDictData (dictId, params) {
      if (params == null) {
        return Promise.reject();
      }
      let filterDtoList = Object.keys(params).map(key => {
        return {
          columnName: key,
          columnValue: params[key]
        }
      });
      return new Promise((resolve, reject) => {
        ReportDictController.listDictData(this, {
          dictId: dictId,
          filterDtoList
        }).then(res => {
          resolve(res.data);
        }).catch(e => {
          reject(e);
        });
      });
    },
    listColumnData (datasetId, columnId) {
      return new Promise((resolve, reject) => {
        ReportDatasetController.listDataWithColumn(this, {
          datasetId: datasetId,
          columnId: columnId
        }).then(res => {
          resolve(res.data);
        }).catch(e => {
          reject(e);
        });
      });
    },
    loadDatasetInfo (datasetId) {
      return new Promise((resolve, reject) => {
        let params = {
          datasetId: datasetId
        }
        ReportDatasetController.view(this, params).then(res => {
          try {
            let info = JSON.parse(res.data.datasetInfo);
            res.data.datasetParamList = info.paramList;
            res.data.columnList = info.columnList || res.data.columnList;
          } catch (e) {
            res.data.datasetParamList = [];
          }
          resolve(res.data);
        }).catch(e => {
          reject(e);
        });
      });
    },
    gotoPage (pageId, params) {
      this.showSubPage = true;
      this.subPageId = pageId;
      this.subPageParams = JSON.stringify(params || {});
    },
    gotoRouter (routerName, routerParams) {
      let menuItem = findTreeNode(this.getMenuList, routerName, 'formRouterName');
      if (menuItem != null) {
        // 查找要跳转的是不是菜单，如果是执行菜单选中操作
        this.setCurrentMenuId(menuItem.menuId);
      } else {
        // 如果跳转的路由不是菜单，跳转过去
        this.$router.push({
          name: routerName,
          query: routerParams.query,
          param: routerParams.param
        });
      }
    },
    onChartDblClick (widget, data) {
      if (widget != null && Array.isArray(widget.operationList)) {
        // 下钻事件
        let drillOperation = findItemFromList(widget.operationList, this.SysCustomWidgetOperationType.DRILL, 'type');
        if (drillOperation != null && drillOperation.enabled) {
          let pageId = drillOperation.pageId;
          let filterList = drillOperation.filterList;
          let params = {};
          if (Array.isArray(filterList)) {
            let dataset = this.datasetMap.get(widget.props.datasetInfo.datasetId);
            params = filterList.reduce((retObj, item) => {
              if (item.filterValueType === this.FilterValueKind.DRILL_DATA && dataset) {
                if (widget.props && widget.props.datasetInfo) {
                  let columnId = item.paramValue;
                  let column = findItemFromList(dataset.columnList, columnId, 'columnId');
                  // 维度字段
                  if (Array.isArray(widget.props.datasetInfo.categroyColumnList)) {
                    let category = findItemFromList(widget.props.datasetInfo.categroyColumnList, columnId, 'columnId');
                    if (category != null) {
                      retObj[item.paramName] = data[column.columnName];
                    }
                  }
                  // 指标字段
                }
              } else {
                retObj[item.paramName] = this.getQueryParam(item);
              }
              return retObj;
            }, {});
          }
          this.gotoPage(pageId, params);
          return;
        }
        // 路由跳转操作
        let routeOperation = findItemFromList(widget.operationList, this.SysCustomWidgetOperationType.ROUTE, 'type');
        if (routeOperation != null && !this.isEdit && routeOperation.enabled) {
          let queryParams = (routeOperation.routeParams || []).reduce((retObj, item) => {
            if (item.valueType === 'fixed') {
              // 固定值
              retObj[item.paramName] = item.paramValue;
            } else if (item.valueType === 'bind') {
              // 绑定到字段
              let columnName;
              if (widget.dataset) {
                let column = findItemFromList(widget.dataset.columnList, item.paramValue, 'columnId');
                if (widget.dataset.datasetType === this.DatasetType.API) {
                  columnName = [];
                  do {
                    columnName.push(column.columnName);
                    column = findItemFromList(widget.dataset.columnList, column.parentId, 'columnId');
                  } while (column == null);
                  columnName = columnName.reverse();
                } else {
                  columnName = (column || {}).columnName;
                }
              }
              let value = this.getDataString(columnName, data);
              if (value) retObj[item.paramName] = value;
            }
            return retObj;
          }, {});
          this.gotoRouter(
            routeOperation.routeName,
            {
              query: queryParams
            })
        }
      }
    },
    // 根据配置的字段取字符串数据
    getDataString (columnName, data) {
      if (Array.isArray(columnName)) {
        let dataValue = columnName.length > 0 ? data : undefined;

        for (let i = 0; i < columnName.length; i++) {
          let name = columnName[i];
          if (name == null || dataValue == null) {
            dataValue = undefined;
            break;
          }
          dataValue = dataValue[name];
        }
        return dataValue;
      } else {
        return data[columnName];
      }
    },
    ...mapMutations(['setCurrentMenuId'])
  },
  computed: {
    filterWidgetTypeList () {
      return [
        this.SysCustomWidgetType.MobileInputFilter,
        this.SysCustomWidgetType.MobileRadioFilter,
        this.SysCustomWidgetType.MobileCheckBoxFilter,
        this.SysCustomWidgetType.MobileSwitchFilter,
        this.SysCustomWidgetType.MobileDateRangeFilter,
        this.SysCustomWidgetType.MobileNumberRangeFilter
      ];
    },
    getAllWidget () {
      if (Array.isArray(this.formConfig.widgetList)) {
        return getAllWidgetList(this.formConfig.widgetList);
      }

      return [];
    },
    formParams () {
      let params = {};
      try {
        if (this.params) params = JSON.parse(this.params);
      } catch (e) {
        console.log(e);
      }
      return params;
    },
    filterWidgetList () {
      return this.getAllWidget.filter(widget => {
        return this.filterWidgetTypeList.indexOf(widget.widgetType) !== -1;
      });
    },
    chartWidgetList () {
      return this.getAllWidget.filter(widget => {
        return this.filterWidgetTypeList.indexOf(widget.widgetType) === -1;
      });
    },
    ...mapGetters(['getUserInfo', 'getMenuList'])
  },
  watch: {
    'formConfig': {
      handler () {
        if (this.formConfig == null) return;
        this.isReady = false;
        this.datasetMap = new Map();
        this.initFormData().then(res => {
          this.isReady = true;
        }).catch(e => {
          Notify({ type: 'danger', message: '页面初始化失败！' });
        });
      },
      immediate: true
    }
  }
}
</script>

<style scoped>
  .online-report-form {
    height: 100vh;
    display: flex;
    flex-direction: column;
    background: #F6F7F9;
  }
  .main-box {
    padding: 16px;
    background: #F6F7F9;
    flex-grow: 1;
    flex-shrink: 1;
    height: 200px;
    overflow-y: auto;
  }
</style>

<style>
  .filter-item + .filter-item {
    margin-top: 10px;
  }
</style>
